Workshop: Datenvisualisierung mit ggplot2

Tag I

Author
Affiliation

Arieja Farugie & Luca Schnatz

Institut für Psychologie

Published

October 5, 2023

Datensatz laden

Zunächst laden wir den Datensatz. Dieser ist als .rds Datei abgespeichert (ein R-spezifisches Datenformat), weswegen wir sie mit dem Befehl readRDS() in R einladen können. Mit glimpse() können wir einen Überblick über die verschiedenen Variablen erhalten.

```{r}
#| message: false
library(tidyverse)


exercise_data <- readRDS(url("https://github.com/jlschnatz/WoMepS_DataVizR/raw/main/clean_exercise_data.rds"))

glimpse(exercise_data)
```
#> Rows: 3,471
#> Columns: 32
#> $ id_participant                       <dbl> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11…
#> $ geschlecht                           <fct> weiblich, weiblich, maennlich, ma…
#> $ alter                                <dbl> 33, 50, 56, 61, 59, 56, 66, 25, 5…
#> $ familienstand                        <fct> ledig, verheirat.zusam.leb., verh…
#> $ nettoeinkommen_frei                  <dbl> 1800, 1100, 2500, NA, 1000, NA, 1…
#> $ nettoeinkommen_binned                <fct> 1750 - 1999 euro, 1000 - 1124 eur…
#> $ aequivalenzeinkommen                 <dbl> 1800, 2467, 1750, 4167, 1000, 466…
#> $ konfession                           <fct> evang.ohne freikirch, keiner reli…
#> $ erwerb_1                             <fct> erwerbstaetig, erwerbstaetig, erw…
#> $ erwerb_2                             <fct> "erwerbstaetig", "erwerbstaetig",…
#> $ schulabschluss                       <fct> "hochschulreife", "mittlere reife…
#> $ berufstaetig                         <fct> hauptberufl.ganztags, hauptberufl…
#> $ berufliche_stellung                  <fct> "angestellter", "angestellter", "…
#> $ staatsbuergerschaft                  <fct> deutschland, deutschland, deutsch…
#> $ deutsch_staats                       <fct> "ja", "ja", "ja", "ja", "ja", "ja…
#> $ bundesland                           <fct> mecklenb.-vorpommern, thueringen,…
#> $ ost_west                             <fct> neue bundeslaender, neue bundesla…
#> $ subj_schichteinstufung               <fct> mittelschicht, mittelschicht, unt…
#> $ bmi                                  <dbl> 23.53, 28.23, 24.77, 38.87, 30.82…
#> $ ps_01_gehetzt                        <int> 4, 4, 3, 2, 1, 2, 4, 2, 1, 3, 3, …
#> $ ps_02_niedergeschlagen               <int> 1, 4, 2, 3, 1, 2, 2, 3, 1, 1, 1, …
#> $ ps_03_ausgeglichen                   <int> 2, 4, 2, 2, 1, 4, 4, 3, 2, 2, 1, …
#> $ ps_04_energetisch                    <int> 2, 4, 2, 3, 1, 5, 2, 2, 3, 3, 3, …
#> $ ps_05_schmerzen                      <int> 1, 3, 1, 4, 1, 1, 4, 1, 4, 3, 1, …
#> $ ps_06_einsam                         <int> 1, 2, 1, 2, 1, 1, 1, 1, 3, 2, 1, …
#> $ ps_07_gesundeinschr_koerperlich_allg <int> 1, 3, 2, 3, 1, 1, 3, 3, 1, 1, 1, …
#> $ ps_08_gesundeinschr_koerperlich_art  <int> 1, 3, 2, 3, 1, 1, 4, 3, 3, 1, 1, …
#> $ ps_09_gesundeinschr_seelisch_allg    <int> 1, 2, 2, 2, 1, 1, 3, 1, 1, 1, 1, …
#> $ ps_10_gesundeinschr_seelisch_art     <int> 1, 1, 2, 2, 1, 1, 4, 1, 1, 1, 1, …
#> $ ps_11_einschr_sozial                 <int> 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, …
#> $ lebenszufriedenheit                  <dbl> 8, 8, 5, 8, 8, 8, 8, 8, 10, 8, 8,…
#> $ psychological_distress               <int> 16, 31, 20, 29, 11, 20, 32, 21, 2…

Basics Plots in ggplot2

An Tag 1 des Workshops geht es vor allem darum, dass Sie die wichtigsten “Basic”-Plots in ggplot2 kennenlernen und in nachfolgenden Aufgaben anwenden und ausprobieren. Das Skript ist dabei nach den verschiedenen Datentypen (kategorisch, numerisch, und die Kombinationen aus beiden) strukturiert, da es für jeden Datentyp spezifische Plots gibt, die üblicherweise verwendet werden und die Daten am besten repräsentieren.

Jede ggplot2-Abbildung fängt dabei immer mit dem gleichen leicht zu merkenden Befehl an: ggplot(). In diesem Befehl können wir bereits die Daten spezifizieren, die wir visualisieren wollen und die Aesthetics definieren. Diese repräsentieren die Zuordnung von Variablen aus dem Datensatz zu verschiedenen visuellen Eigenschaften des Plots (z.B. x, y, color, fill, shape, size, etc.).

```{r}
ggplot(
  data = exercise_data,
 #mapping = aes(...)
) 
```

Wie Sie sehen, erscheint zunächst einfach ein graues Panel, denn wir haben ja noch keine Geometries und Aesthetics definiert.

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(y = alter)
  ) 
```

Durch die Zuordnung der x-Achse zu der Variable alter im Datensatz, erscheint nun in unserem Plot die Variable auf der x-Achse. Aestethics werden dabei immer über den Befehlt mapping = aes(...) definiert. Da aber noch keine Geometries festgelegt sind, werden die Daten noch nicht im Plot visualisiert.

1 Variable (Numerisch)

Wir beginnen mit einer numerische Variable (z.B. Psychologischer Distress, Alter, Body-Mass-Index, Nettoeinkommen).

Boxplot

Der Boxplot ist eine recht übersichtliche Art der Darstellung von Verteilungen (für mindestens ordinalskalierte Variablen). Als praktisches Beispiel wollen wir uns anschauen wie die Variable psychologischer Distress in den Daten verteilt ist. Wie bereits erwähnt, können wir in den ggplot()-Befehl den Datensatz und die Aesthetics definieren. Wenn Sie einen vertikalen Boxplot generieren wollen, müssen Sie dabei in den Aesthetics aes(y = psychological_distress) eingeben, da wir die y-Achse der Variable psychologischer Distress zuordnen. Danach können wir über den Befehl geom_boxplot() den Boxplot erstellen.

```{r}
ggplot(
  data = exercise_data,
  aes(y = psychological_distress)
  ) +
  geom_boxplot()

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_boxplot()
```

Histogramm

Ein Histogramm können wir ganz analog zu dem Boxplot definieren, indem wir einfach den Befehl geom_boxplot() austauschen mit dem Befehl geom_histogram(). Wichtig zu beachten bei Histogrammen ist, dass Anzahl der Kategorien (bins) eine Auswirkung auf die Optik des Plots hat. Es lohnt sich also verschiedene Bingrößen bzw. Anzahl an Bins auszuprobieren und die Anzahl zu wählen, die die Daten am besten repräsentiert. Wir können die Anzahl an Bins mit dem Argument bins = ... spezifizieren und die Bingröße über das Argument binwidth = ....

```{r}
exercise_data %>%
  drop_na(psychological_distress) %>%
  ggplot(aes(x = psychological_distress)) + 
  geom_histogram()

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_histogram()

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_histogram(bins = 10)

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_histogram()
```

Density-Plot

Eine weitere Methode, um die Verteilung einer numerischen Variable zu visualisieren, ist der Density-Plot. Dabei wird in einem Density-Plot eine Kernel-Dichte-Schätzung verwendet, um die Wahrscheinlichkeitsdichtefunktion der Variable darzustellen. In ggplot2 können wir sehr einfach einen Density-Plot mit der Funktion geom_density() definieren. Sie sehen, dass die Geometries (also die Spezifikation, welcher Art des Plots verwendet werden soll) in ggplot2 alle mit geom_… beginnen. So sind sie recht einfach einzuprägen. Bei Density-Plots können wir mit dem Argument bw = ... die Bandwith definieren, also wie sehr sich der Plot an unserer Daten anpassen soll (wie genau die Dichte der Verteilung entsprechen soll). Ggplot2 wählt hier meistens schon gute Default-Werte, probieren Sie aber im Zweifel trotzdem verschiedene Werte aus, um zu schauen wie sich der Plot verändert.

```{r}
ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_density()

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_density(bw = .4)

ggplot(
  data = exercise_data,
  aes(x = psychological_distress)
  ) +
  geom_density(bw = 3)
```

1 Variable (Kategorisch)

Als nächsten gehen über zu Visualisierungen für eine kategorische Variable (z.B. Geschlecht, Bundesland, etc.). Hier bieten sich vor allem zwei verschiedene Plots an: Häufigkeitsdiagramme (Barplots) und Kuchendiagramme (Pie-Charts).

Barplot

Die Verwendung von Barplots ist insbesondere dann sinnvoll, wenn wir die Häufigkeit (absolut oder relativ) einer kategorischen Variable darstellen wollen. Wir müssen dafür nur in den Aesthetics die kategorische Variable entwender der x oder y-Achse zuordnen (mapping = aes(x/y = …)). Danach können wir mit dem Befehl geom_bar() den Barplot definieren. Das Argument stat = "count" ist dabei der Default, müsste also theoretisch nicht spezifiziert werden. Es macht allerdings den Code expliziter und dadurch verständlicher. Wenn wir statt absoluter Häufigkeiten relative Häufigkeiten darstellen wollen, müssen wir dies bereits in den Aesthetics definieren. Die Schreibweise y = after_stat(count/sum(count)) ist dabei folgendermaßen zu lesen: Auf der y-Achse soll die Anzahl einer Kategorie durch die Summe aus der Anzahl aller Kategorien geteilt werden (relative Häufigkeit).

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung)
  ) + 
  geom_bar(stat = "count")

count(exercise_data, subj_schichteinstufung) %>%
  ggplot(
    data = .,
    mapping = aes(x = subj_schichteinstufung, y = n)
    ) + 
  geom_bar(stat = "identity") # äquivalent zu vorherigem Plot

ggplot(
  data = exercise_data,
  mapping = aes(y = subj_schichteinstufung)
  ) + 
  geom_bar(stat = "count")

# relative Häufigkeit
ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung,
                y = after_stat(count/sum(count)))
  ) + 
  geom_bar()
```

Kuchendiagramm (Pie-Chart)

Ein Kuchendiagramm ist in ggplot2 letzendlich nur ein abgewandelter Barplot, bei dem die Säulen des Plots einem polaren Koordinatensystem zugeordnet werden. Bevor wir das Kuchendiagramm visualisieren können, müssen wir in diesem Fall die Häufigkeiten der Kategorien (z.B. der Konfession) schon im Vorhinein berechen. Dies geht sehr leicht mit der Funktion count() aus dem dplyr-Package. Danach können wir die Häufigkeit der Kategorien (die Variable n) der y-Achse in den Aesthetics zuordnen. Mit der Aesthethic fill = konfession wird die Variable in unserem Datensatz über die Farbfüllung im Plot dargestellt. Mittels coord_polar(theta = "y") wird das kartesische Koordinatensystem in ein polares Koordinatensystem umgewandelt, um das Kuchendiagramm zu erstellen.

```{r}
exercise_data %>%
  count(konfession) %>% # Bestimmung der Häufigkeiten der Konfession
  drop_na(konfession) %>% # NAs rausschmeißen
  ggplot(
    data = .,
    mapping = aes(x = "", 
                  y = n, # Häufigkeit
                  fill = konfession) # Kategorie
  ) + 
  geom_bar(stat = "identity") + # "identity" statt "count"
  coord_polar(theta = "y") 
```

2 Variablen (Numerisch, Numerisch)

Nachdem Sie einige Plots für die Visualisierung für nur eine Variable (numerisch oder kategorisch) kennengelernt haben, wollen wir uns als nächstes der Visualisierung von zwei Variablen widmen. Wir starten dabei mit der Visualisierung zwei numerischer Variablen.

Scatterplot

Der klassische Plot, um zwei numerische Variablen zu visualisieren, ist der Scatterplot oder auch Streudiagramm genannt. Die Geometry, die Sie dafür benötigen ist geom_point(). Wir definieren einfach die beiden Variablen, die wir visualisieren wollen in den Aesthethics über aes(x = ..., y = ...).

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi)
  ) +
  geom_point()  

# Anpassungsmöglichkeiten 

ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi)
  ) +
  geom_point(alpha = 0.3) # Durchsichtigkeit der Punkte (von alpha = 0-1)

ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi)
  ) +
  geom_point(size = 0.4, alpha = 0.3) # Größe der Punkte


ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi)
  ) +
  geom_point(color = "darkblue") # Farbe der Punkte
```

2 Variablen (Kategorisch, Kategorisch)

Um zwei kategorische Variablen zu visualisieren, bietet sich ebenfalls ein Barplot an. Wir ordnen dabei die eine kategorische Variable einer Achse des Koordinatensystems zu (x oder y) und ordnen die andere Variable der Aesthetic fill oder color zu. Dabei gibt es verschiedenen Möglichkeiten, wie die Säulen visualisiert werden können. Entweder können diese nebeneinander stehen (position = position_dodge(width = 1)) oder aufeinander stehen (position = position_stack()).

Alternativ zu einer Farbzuordnung können Sie auch zwei kategorische Variablen visualisieren, indem Sie mehrere Panels verwenden. Dies kann vor allem bei sehr unübersichtlichen Plots mit vielen Kategorien sinnvoll sein. Mehrere Panels/Facets können Sie definieren über die Funktion facet_wrap() (oder facet_grid(), die hier nicht näher erläutert wird). Sie müssen dabei in diesen Funktionen angeben, auf Basis welcher Variable die Panels erstellt werden sollen. Sie können dafür entweder die Schreibweise facets = ~geschlecht oder facets = vars(geschlecht) verwenden.

```{r}
# Zweite Variable mittels Farbzuordnung
ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung, fill = geschlecht)
  ) + 
  geom_bar(stat = "count", position = position_dodge(width = 1))

ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung, fill = geschlecht)
  ) + 
  geom_bar(stat = "count", position = position_stack())

# Definition von verschiedenen Panels statt Farbzuordnung

ggplot(
  data = exercise_data,
  mapping = aes(y = subj_schichteinstufung)
  ) + 
  geom_bar(stat = "count", position = position_dodge(width = 1)) + 
  facet_wrap(facets = vars(geschlecht)) # mehrere Panels


ggplot(
  data = exercise_data,
  mapping = aes(y = subj_schichteinstufung)
  ) + 
  geom_bar(stat = "count", position = position_dodge(width = 1)) +
  facet_grid(
    rows = vars(geschlecht),
    cols = vars(familienstand)
  )

ggplot(
  data = exercise_data,
  mapping = aes(y = geschlecht)
  ) + 
  geom_bar(stat = "count", position = position_dodge(width = 1)) + 
  facet_wrap(facets = ~subj_schichteinstufung) # Alternativ Schreibweise: facets = vars(subj_schichteinstufung)
```

2 Variablen (Numerisch, Kategorisch)

Für eine Visualisierung mit einer numerischen und einer kategorischen Variable können Sie auf die Plots zurückgreifen, die Sie schon im Teil Visualisierung mit einer numerischen Variable kennengelernt haben. Für das Beispiel des Boxplots ordnen Sie einfach zusätzlich in den Aesthetics die kategorische Variable entweder x oder y zu. Wenn Sie einen Density-Plot verwenden wollen, können sie die Aesthetics fill oder color der kategorischen Variable zuordnen.

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung,
                y = psychological_distress)
  ) + 
  geom_boxplot()

ggplot(
  data = exercise_data,
  mapping = aes(x = psychological_distress,
                fill = subj_schichteinstufung)
  ) + 
  geom_density(alpha = 0.1)


# Exkurs
library(ggridges)
ggplot(data = exercise_data,
       mapping = aes(x = psychological_distress,
                     y = subj_schichteinstufung,
                     fill = subj_schichteinstufung
                     )) + 
  geom_density_ridges()

# für mehr Infos s.h.: https://wilkelab.org/ggridges/
```

Mehr als zwei Variablen

Für Plots mit mehr als zwei Variablen können Sie die bisher vorgestellten Konzepte gemeinsam kombinieren. x, y, color, fill, shape können dabei den verschiedenen Variablen zugeordnet werden. Ebenfalls können Sie die vorher vorgestellten Multipanel-Funktion nutzen (facet_wrap oder facet_grid). Hier ein paar Beispiele:

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi,
                color = geschlecht,
              #  shape = geschlecht
                )
) + 
  geom_point()

ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi)
                
  ) + 
  geom_point() + 
  facet_grid(cols = vars(geschlecht)) 

ggplot(
  data = exercise_data,
  mapping = aes(x = alter,
                y = bmi,
                color = geschlecht)
) + 
  geom_point() + 
  facet_grid(cols = vars(geschlecht)) 

```

```{r}
ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung,
                y = psychological_distress,
                fill = geschlecht)
  ) + 
  geom_boxplot()

ggplot(
  data = exercise_data,
  mapping = aes(x = subj_schichteinstufung,
                y = psychological_distress)
  ) + 
  geom_boxplot() + 
  facet_wrap(~geschlecht)
```